using System.Net;
using System.Reflection;
using System.Security.Authentication;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Unicode;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Autofac.Extras.DynamicProxy;
using Castle.DynamicProxy;
using FreeSql;
using Lazy.Captcha.Core;
using Lazy.Captcha.Core.Generator;
using MailKit;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.FileProviders;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using NLog.Web;
using Publicuse.Autofac;
using Publicuse.Autofac.AOP;
using Publicuse.Entity;
using Publicuse.Entity.sqlsugar;
using Publicuse.Interface;
using Publicuse.Service;
using Publicuse.Util;
using Publicuse.Util.Jwt;
using Publicuse.Util.QuartZ;
using Publicuse.WebCore.AuthorizationExtend;
using Publicuse.WebCore.CorsExtend;
using Publicuse.WebCore.JsonExtend;
using Publicuse.WebCore.LogExtend;
using Publicuse.WebCore.ResponseExtend;
using Publicuse.WebCore.SwaggerExtend;
using Quartz;
using Quartz.Impl;
using SixLabors.ImageSharp;
using Geekeradmin;
using Geekeradmin.Authorize;
using Geekeradmin.Common;
using Geekeradmin.Entitys;
using Geekeradmin.ExtendsService;
using Geekeradmin.Filters;
using Geekeradmin.Middleware;
using Geekeradmin.ResultExtension;
using SqlSugar;
using ApiBehaviorOptions = Microsoft.AspNetCore.Mvc.ApiBehaviorOptions;

try
{
  var builder = WebApplication.CreateBuilder(args);
  builder.WebHost.UseKestrel(a =>
  {
    a.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(60);
    a.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(60);
    a.Limits.MaxConcurrentUpgradedConnections = 104857600;
    a.Limits.MaxResponseBufferSize = null;
    a.Limits.MaxRequestHeaderCount = 104857600;
    a.Limits.MaxRequestHeadersTotalSize = 104857600;
    a.Limits.MaxConcurrentConnections = 104857600;

    a.Limits.MaxRequestBufferSize = null;
    a.Limits.MaxRequestLineSize = 104857600;
    a.Limits.MaxRequestBodySize = null;
    a.ConfigureHttpsDefaults(i =>
    {
      i.SslProtocols =
        System.Security.Authentication.SslProtocols.Tls12
        | System.Security.Authentication.SslProtocols.Tls13;
      i.ServerCertificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(
        "ConfigFile/gzticc.pfx",
        "gzticc"
      );
    });
  });
  builder.WebHost.ConfigureKestrel(
    (context, options) =>
    {
      options.Limits.MaxRequestBodySize = null;
      options.Limits.MaxRequestBufferSize = null;
      options.Limits.MaxResponseBufferSize = null;
    }
  );

  #region 系统后台执行定时任务
  builder.Services.AddHostedService<ClearLogService>();
  builder.Services.AddHostedService<ClearLoginService>();
  builder.Services.AddHostedService<DowntaskService>();
  builder.Services.AddHostedService<DatacacheService>();
  builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
  builder.Services.AddHttpClient();
  builder.Services.AddHttpContextAccessor();
  //builder.Services.AddHostedService<QuartzService>();
  //builder.Services.AddTransient<HttpResultfulJob>();
  //builder.Services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();
  //builder.Services.AddSingleton<Quartz.Spi.IJobFactory, IOCJobFactory>();
  #endregion


  //添加全局拦截器
  builder
    .Services.Configure<KestrelServerOptions>(x => x.AllowSynchronousIO = true)
    .Configure<IISServerOptions>(x => x.AllowSynchronousIO = true);

  #region 读取配置文件
  IConfiguration configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
  builder.Services.AddSingleton(new AppConfigUtil(configuration));
  #endregion

  #region 配置可以同步请求读取流数据
  builder
    .Services.AddDistributedMemoryCache()
    .AddCaptcha(
      configuration,
      option =>
      {
        //var today = DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd HH:mm:ss");
        var ctype = 1;
        Color color = new Color();
        var httpreq = HttpContextExtendBase.Current.Request.QueryString.ToString();
        if (!string.IsNullOrEmpty(httpreq))
        {
          var qstring = httpreq.Split('?')[1].Split('&');
          if (qstring.Length >= 2)
          {
            ctype = qstring[1].Split('=')[1].GetIntValue();
            if (ctype == 2)
            {
              color = Color.White;
            }
          }
          else
          {
            color = Color.Black;
          }
        }
        else
        {
          color = Color.Black;
        }

        var gsg = EnDecryptionUtil.DESEncryptionb("ajng");

        //Console.WriteLine("当前请求信息："+ ctype);
        option.CaptchaType = CaptchaType.NUMBER; // 验证码类型
        option.CodeLength = 4; // 验证码长度, 要放在CaptchaType设置后
        option.ExpirySeconds = 300; // 验证码过期时间
        option.IgnoreCase = true; // 比较时是否忽略大小写
        option.ImageOption.Animation = false; // 是否启用动画

        option.ImageOption.Width = 100; // 验证码宽度
        option.ImageOption.Height = 48; // 验证码高度
        option.ImageOption.BackgroundColor = SixLabors.ImageSharp.Color.Transparent; // 验证码背景色

        option.ImageOption.BubbleCount = 0; // 气泡数量
        option.ImageOption.BubbleMinRadius = 3; // 气泡最小半径
        option.ImageOption.BubbleMaxRadius = 10; // 气泡最大半径
        option.ImageOption.BubbleThickness = 1; // 气泡边沿厚度

        option.ImageOption.InterferenceLineCount = 0; // 干扰线数量

        option.ImageOption.FontSize = 28; // 字体大小
        List<Color> colors = new List<Color>() { color };
        //option.ImageOption.ForegroundColors = colors; // 字体颜色
        option.ImageOption.FontFamily = DefaultFontFamilys.Instance.Kaiti; // 字体，中文使用kaiti，其他字符可根据喜好设置（可能部分转字符会出现绘制不出的情况）。
      }
    );
  #endregion

  #region 注入SqlSugar
  builder.Services.AddSingleton<ISqlSugarClient>(ServiceProvider =>
  {
    var constr = AesEncryptionUtil.AESDecrypt(
      builder.Configuration.GetConnectionString("MySqlSugarConnection"),
      out var msg
    );
    SqlSugarScope db = new SqlSugarScope(
      new ConnectionConfig()
      {
        DbType = DbType.MySql,
        IsAutoCloseConnection = true,
        ConnectionString = constr
      }
    );
    return db;
  });
  #endregion

  #region 注入IFreeSql
  builder.Services.AddSingleton<IFreeSql>(ServiceProvider =>
  {
    FreeSqlBuilder builder = new FreeSqlBuilder();
    IConfiguration IConfiguration = ServiceProvider.GetService<IConfiguration>();
    var mysql = new CustomConnectionConfig();
    IConfiguration.Bind("MySqlConnectionString", mysql);
    builder.UseConnectionString(
      DataType.MySql,
      AesEncryptionUtil.AESDecrypt(mysql.MasterConnectionString, out var msg)
    );
    IFreeSql freeSql = builder.Build();
    return freeSql;
  });
  #endregion

  builder.Services.Configure<DBConnectionOption>(configuration.GetSection("ConnectionStrings"));

  builder.Services.Configure<FormOptions>(x =>
  {
    x.MultipartBodyLengthLimit = int.MaxValue;
  });

  #region 关闭参数自动校验,我们需要返回自定义的格式
  builder.Services.Configure<ApiBehaviorOptions>(
    (o) =>
    {
      o.SuppressModelStateInvalidFilter = true;
    }
  );
  #endregion

  var sg = AesEncryptionUtil.Encrypt("Gzxx@123");
  var jmkey = EnDecryptionUtil.DESEncryption("Geekeradmin2025");
  var pass = EnDecryptionUtil.DESEncryptionb(jmkey);
  var accessright = EnDecryptionUtil.DESDecryptb(pass);

  // 添加全局拦截器
  builder
    .Services.AddControllersWithViews(
      (opt) =>
      {
        opt.Filters.Add<CustomException>();
        opt.Filters.Add<CustomLogAction>();
        opt.Filters.Add<CustomGlobal>();
        opt.Filters.Add<CustomResult>();
      }
    )
    .AddRazorRuntimeCompilation() // 修改view后自动重新编译运行
    .AddXmlSerializerFormatters()
    .AddJsonExt();

  builder.Services.AddAuthorization(options =>
  {
    options.AddPolicy(
      "UserApp",
      policyBuilder =>
      {
        policyBuilder.Requirements.Add(new UserAuthorizationRequirement());
      }
    );
  });

  #region jwt鉴权授权
  builder.RegisterAuthorization();
  #endregion

  builder.Services.AddDirectoryBrowser(); //允许目录浏览
  builder.Services.AddTransient<IAuthorizationHandler, UserAuthorizationHandler>();
  builder.Services.AddEndpointsApiExplorer();

  #region 返回结果扩展
  //注册自定义返回类型Result
  builder.Services.TryAddSingleton<
    IActionResultExecutor<NameValueResult>,
    NameValueResultExecutor
  >();
  #endregion

  #region 配置Swagger
  builder.Services.AddSwaggerExt("后台管理系统Api文档", "后台管理系统Api文档");
  #endregion

  #region 添加跨域策略
  builder.Services.AddCorsExt();
  #endregion

  builder.Services.Configure<KestrelServerOptions>(options =>
  {
    options.AllowSynchronousIO = true;
  });

  builder.Services.Configure<IISServerOptions>(options =>
  {
    options.AllowSynchronousIO = true;
  });

  #region 启用压缩/启用缓存
  builder.Services.AddResponseExt();
  #endregion

  builder.Services.AddAntiforgery(o => o.SuppressXFrameOptionsHeader = true);

  #region Autfaoc整合ASP.NET Core
  builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()); //通过工厂替换，把Autofac整合进来
  builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
  {
    containerBuilder.RegisterModule<CustomAutofacModule>();
  });
  //支持控制器的实例让IOC容器来创建---autofac来创建
  builder.Services.Replace(
    ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>()
  );
  #endregion

  //解决中文输出后被编码了，设置支持所有字符集
  builder.Services.Configure<Microsoft.Extensions.WebEncoders.WebEncoderOptions>(options =>
  {
    options.TextEncoderSettings = new System.Text.Encodings.Web.TextEncoderSettings(
      System.Text.Unicode.UnicodeRanges.All
    );
  });
  builder.Services.AddSingleton(HtmlEncoder.Create(UnicodeRanges.All));

  builder.Services.AddSession();

  #region 开启日志记录
  //builder.Logging.AddFilter("System", LogLevel.Warning);  //忽略系统日志
  //builder.Logging.AddFilter("Microsoft", LogLevel.Warning);   //忽略系统日志
  //builder.Logging.AddLog4Net("ConfigFile/log4net.Config");
  //builder.Logging.AddNLog("ConfigFile/NLog.config");

  //builder.Log4Register(); //log4net应用
  //builder.NLogRegister();//Nlog应用
  #endregion

  var app = builder.Build();
  app.UseCorsExt();

  #region 启用X-XSS-Protection
  app.UseXssMiddleware();
  #endregion

  app.Use(
    async (context, next) =>
    {
      context.Request.EnableBuffering();
      context.Response.Headers.Add("X-Frame-Options", "ALLOW-FROM uri");
      if (!context.Response.HasStarted)
      {
        await next(); //走正常流程
      }
    }
  );
  //启用压缩
  app.UseResponseCompression();
  //启用缓存
  app.UseResponseCaching();

  app.UseForwardedHeaders(
    new ForwardedHeadersOptions
    {
      ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
    }
  );

  // Configure the HTTP request pipeline.
  if (!app.Environment.IsDevelopment())
  {
    app.UseExceptionHandler("/Home/Error");
  }
  else
  {
    app.UseSwaggerExt("后台管理系统Api文档");
  }
  //app.UseHttpsRedirection();

  #region 鉴权授权
  app.UseAuthentication();
  app.UseRouting();
  app.UseAuthorization(); //授权
  #endregion

  #region 配置WebSockets
  app.UseWebSockets(new WebSocketOptions { KeepAliveInterval = new TimeSpan(0, 10, 0) });
  #endregion

  app.UseSession();

  #region  中间件，这里就是配置读取静态文件的地方
  app.UseStaticFiles(
    new StaticFileOptions()
    {
      //不限制content-type下载
      ServeUnknownFileTypes = true,
      FileProvider = new PhysicalFileProvider(
        Path.Combine(Directory.GetCurrentDirectory(), @"wwwroot")
      ),
    }
  );
  #endregion

  #region 启动静态文件浏览
  app.UseDirectoryBrowser(
    new DirectoryBrowserOptions
    {
      FileProvider = new PhysicalFileProvider(
        Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images")
      ),
      RequestPath = "/MyImages"
    }
  );
  #endregion

  app.UseAMiddleWare().UseStaticHttpContext(); //ע注入中间件
  app.MapControllerRoute(name: "default", pattern: "{controller=Angular}/{action=Index}/{id?}");

  app.Run();
}
catch (Exception ex)
{
  var msg = ex.Message;
}
